package com.liked.task;

import com.alibaba.fastjson.JSON;
import com.common.constant.RedisKey;
import com.common.context.UserContext;
import com.common.domain.po.CollectRecord;
import com.common.domain.po.LikedRecord;
import com.common.exception.CodeAndMsg;
import com.common.exception.JavaSmException;
import com.liked.service.CollectRecordService;
import com.liked.service.LikedRecordService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 路亚
 * @version 0.1
 * @className AddTask
 * @description
 * @date 2024/12/31 10:12
 * @since jdk11
 */
@Component
@RequiredArgsConstructor
public class AddTask {

    private final StringRedisTemplate stringRedisTemplate;

    private final LikedRecordService likedRecordService;

    private final CollectRecordService collectRecordService;

    @XxlJob("addTask")
    public void addTask() {
        // 添加分布式锁，解决注意集群下，任务重复执行的问题
        String likedRecordAddLockKey = RedisKey.LIKED_ADD_LOCK_KEY;
        String lock = stringRedisTemplate.opsForValue().get(likedRecordAddLockKey);
        if (lock != null) {
            return;
        }
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(likedRecordAddLockKey, "lock", 60, TimeUnit.SECONDS);
        if (!flag) {
            throw new JavaSmException(CodeAndMsg.SERVICE_BUSY);
        } else {
            // 开一个守护线程，为分布式锁续命
            Thread t = new Thread(() -> {
                try {
                    int retryTimes = 0;//记录延期次数
                    while (true) {
                        if (retryTimes == 5) {
                            //TODO 如果延期5次，就通知管理人员
                            break;
                        }
                        //每5秒查看一下锁的过期时间，如果小于10秒，延期
                        Thread.sleep(5 * 1000);
                        Long expire = stringRedisTemplate.getExpire(likedRecordAddLockKey);
                        if(expire == -2){//表示key不存在
                            break;
                        }
                        if(expire < 10){
                            //重新设置失效时间
                            stringRedisTemplate.expire(likedRecordAddLockKey, 20, TimeUnit.SECONDS);
                            retryTimes++;
                        }
                    }
                }catch (Exception e){
                    throw new JavaSmException(CodeAndMsg.SERVICE_BUSY);
                }
            });
            t.setDaemon(true);//当主线程结束后，守护线程自动结束
            t.start();
            String addKey = RedisKey.LIKED_ADD_KEY;
            List<String> list = stringRedisTemplate.opsForList().range(addKey, 0, -1);
            List<LikedRecord> likedRecordList = list.stream().map(item -> JSON.parseObject(item, LikedRecord.class)).collect(Collectors.toList());
            List<LikedRecord> isAdd = new ArrayList<>();
            for (LikedRecord likedRecord : likedRecordList) {
                Set<Object> keys = stringRedisTemplate.opsForHash().keys(RedisKey.LIKED_IS_LIKED_KEY + likedRecord.getVideoItemId());
                for (Object key : keys) {
                    String str = (String) stringRedisTemplate.opsForHash().get(RedisKey.LIKED_IS_LIKED_KEY + likedRecord.getVideoItemId(), key.toString());
                    if ("0".equals(str)){
                        LikedRecord isAddLikedRecord = new LikedRecord();
                        isAddLikedRecord.setVideoItemId(likedRecord.getVideoItemId());
                        isAddLikedRecord.setUserId(Long.parseLong(key.toString()));
                        isAdd.add(isAddLikedRecord);
                        stringRedisTemplate.opsForHash().delete(RedisKey.LIKED_IS_LIKED_KEY + likedRecord.getVideoItemId(), key.toString());
                    }
                }
            }
            List<LikedRecord> collect = likedRecordList.stream().filter(likedRecord -> {
                for (LikedRecord record : isAdd) {
                    if (record.getVideoItemId().equals(likedRecord.getVideoItemId()) && record.getUserId().equals(likedRecord.getUserId())) {
                        return false;
                    } else {
                        return true;
                    }
                }
                return true;
            }).collect(Collectors.toList());
            likedRecordService.saveBatch(collect);
            // 添加成功，清除redis列表
            stringRedisTemplate.delete(addKey);
            // 并且把添加成功的，redis对应的值改为2
            for (LikedRecord likedRecord : collect) {
                String isLikedKey = RedisKey.LIKED_IS_LIKED_KEY + likedRecord.getVideoItemId();
                stringRedisTemplate.opsForHash().put(isLikedKey, likedRecord.getUserId() + "", "2");
            }
            //3. 释放锁
            stringRedisTemplate.delete(likedRecordAddLockKey);
        }
    }

    @XxlJob("addCollectRecordTask")
    public void addCollectRecordTask() {
        // 添加分布式锁，解决注意集群下，任务重复执行的问题
        String collectRecordAddLockKey = RedisKey.COLLECT_ADD_LOCK_KEY;
        String lock = stringRedisTemplate.opsForValue().get(collectRecordAddLockKey);
        if (lock != null) {
            return;
        }
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(collectRecordAddLockKey, "lock", 60, TimeUnit.SECONDS);
        if (!flag) {
            throw new JavaSmException(CodeAndMsg.SERVICE_BUSY);
        } else {
            // 开一个守护线程，为分布式锁续命
            Thread t = new Thread(() -> {
                try {
                    int retryTimes = 0;//记录延期次数
                    while (true) {
                        if (retryTimes == 5) {
                            //TODO 如果延期5次，就通知管理人员
                            break;
                        }
                        //每5秒查看一下锁的过期时间，如果小于10秒，延期
                        Thread.sleep(5 * 1000);
                        Long expire = stringRedisTemplate.getExpire(collectRecordAddLockKey);
                        if(expire == -2){//表示key不存在
                            break;
                        }
                        if(expire < 10){
                            //重新设置失效时间
                            stringRedisTemplate.expire(collectRecordAddLockKey, 20, TimeUnit.SECONDS);
                            retryTimes++;
                        }
                    }
                }catch (Exception e){
                    throw new JavaSmException(CodeAndMsg.SERVICE_BUSY);
                }
            });
            t.setDaemon(true);//当主线程结束后，守护线程自动结束
            t.start();
            String collectAddKey = RedisKey.COLLECT_ADD_KEY;
            List<String> list = stringRedisTemplate.opsForList().range(collectAddKey, 0, -1);
            List<CollectRecord> records = list.stream().map(item -> JSON.parseObject(item, CollectRecord.class)).collect(Collectors.toList());
            List<CollectRecord> isAdd = new ArrayList<>();
            for (CollectRecord collectRecord : records) {
                Set<Object> keys = stringRedisTemplate.opsForHash().keys(RedisKey.COLLECT_IS_COLLECT_KEY + collectRecord.getVideoItemId());
                for (Object key : keys) {
                    String str = (String) stringRedisTemplate.opsForHash().get(RedisKey.COLLECT_IS_COLLECT_KEY + collectRecord.getVideoItemId(), key.toString());
                    if ("0".equals(str)){
                        CollectRecord isAddCollectRecord = new CollectRecord();
                        isAddCollectRecord.setVideoItemId(collectRecord.getVideoItemId());
                        isAddCollectRecord.setUserId(Long.parseLong(key.toString()));
                        isAdd.add(isAddCollectRecord);
                        stringRedisTemplate.opsForHash().delete(RedisKey.COLLECT_IS_COLLECT_KEY + collectRecord.getVideoItemId(), key.toString());
                    }
                }
            }
            List<CollectRecord> collect = records.stream().filter(likedRecord -> {
                for (CollectRecord record : isAdd) {
                    if (record.getVideoItemId().equals(likedRecord.getVideoItemId()) && record.getUserId().equals(likedRecord.getUserId())) {
                        return false;
                    } else {
                        return true;
                    }
                }
                return true;
            }).collect(Collectors.toList());
            collectRecordService.saveBatch(collect);
            // 添加成功，清除redis列表
            stringRedisTemplate.delete(collectAddKey);
            // 并且把添加成功的，redis对应的值改为2
            for (CollectRecord likedRecord : collect) {
                String isLikedKey = RedisKey.COLLECT_IS_COLLECT_KEY + likedRecord.getVideoItemId();
                stringRedisTemplate.opsForHash().put(isLikedKey, likedRecord.getUserId() + "", "2");
            }
            //3. 释放锁
            stringRedisTemplate.delete(collectRecordAddLockKey);
        }
    }
}
